package core;
import java.util.*;
import java.awt.image.*;

public class ClusteringTree {
 
    private ClusteringNode _root;
    private BufferedImage _img;
    int stop;
    
    public ClusteringTree() 
    {
        super();
        _root = new ClusteringNode();
    }
 
    public ClusteringTree(ClusteringNode r, BufferedImage i) 
    {
        super();
        setRoot(r);
        setImg(i);
    }

    public ClusteringNode getRoot() 
    {
        return this._root;
    }
 
    public void setRoot(ClusteringNode rootElement) 
    {
        _root = rootElement;
    }
    
    public void setImg(BufferedImage i)
    {
    	_img = i;
    }
    
    public void buildTree(int k, Vector <Neighborhood> iNeighborhood)
    {
        stop = (int) (iNeighborhood.size() * 0.15);
    	buildNode(k, _root, iNeighborhood);
    }
    
    private void buildNode(int k, ClusteringNode node, Vector <Neighborhood> iNeighborhood)
    {
    	node.setData(iNeighborhood);
    	if (iNeighborhood.size() < 60)
    		return;
    	
    	Vector <Observation> obs = new Vector <Observation>();
    	Iterator iter = iNeighborhood.iterator();
    	while (iter.hasNext())
    		obs.add(new Observation((Neighborhood) iter.next(), 0));
    	
    	KMeans km = new KMeans(k, obs);
    	km.runKMeans(_img);
    	
    	for (int i=0; i < k; i++)
    	{
    		ClusteringNode anode = new ClusteringNode();
    		anode.setMean(km.getMean(i));
    		buildNode(k, anode, km.getPoints(i));
    		node.addChildren(anode);	
    	}
    	
    	
    }
    
    public Neighborhood findClosest(Neighborhood input, BufferedImage output_image)
    {
    	//System.out.print("a");
    	double min = Double.MAX_VALUE;
    	double currentDistance = 0;
    	Neighborhood target = null;
    	ClusteringNode leaf = walk(_root, input, output_image);
    	Iterator iter = leaf.getData().iterator();
    	while (iter.hasNext())
    	{
    		Neighborhood n = (Neighborhood)iter.next();
    		currentDistance = Neighborhood.distance2(input, n, output_image, _img);
    		if (currentDistance < min) 
    		{
    			min = currentDistance;
    			target = n;
    		}
    	}
    	return target;
    }
    
    private ClusteringNode walk(ClusteringNode n, Neighborhood input, BufferedImage output_image)
    {
    	
    	if (n.hasChildren()) 
    	{
    		
    		List children = n.getChildren();
	    	Iterator iter = children.iterator();
	    	double min = Double.MAX_VALUE;
	    	double currentDistance = 0;
	    	ClusteringNode currentNode = null;
	    	while(iter.hasNext()){
	    		ClusteringNode cn = (ClusteringNode) iter.next();
	    		currentDistance = Neighborhood.distance2(input, cn.getMean(), output_image,_img);
	    		if (currentDistance < min) 
	    		{
	    			min = currentDistance;
	    			currentNode = cn;
	    		}
	    		
	    	}
	    	return walk(currentNode, input, output_image);
    	}
    	else return n;
    }
}



